<template>
  <component
    ref="formEl"
    :is="formRegister && !wCheckboxes ? 'w-form-element' : 'div'"
    v-bind="formRegister && { validators, inputValue: isChecked, disabled }"
    v-model:valid="valid"
    @reset="
      $emit('update:modelValue', (isChecked = null));
      $emit('input', null);
    "
    :class="classes"
    ><input
      ref="input"
      :id="`w-checkbox--${_.uid}`"
      type="checkbox"
      :name="inputName"
      :checked="isChecked || null"
      :disabled="disabled || null"
      :required="required || null"
      @focus="$emit('focus', $event)"
      @blur="$emit('blur', $event)"
      @change="
        onInput() /* Edge doesn't fire input on checkbox/radio/select change */
      "
      @keypress.enter="onInput"
      :aria-checked="isChecked || 'false'"
      role="checkbox"
    /><template v-if="hasLabel && labelOnLeft"
      ><label
        class="w-checkbox__label w-form-el-shakable pr2"
        v-if="$slots.default"
        :for="`w-checkbox--${_.uid}`"
      >
        <slot></slot> </label
      ><label
        class="w-checkbox__label w-form-el-shakable pr2"
        v-else-if="label"
        :for="`w-checkbox--${_.uid}`"
        v-html="label"
      ></label
    ></template>
    <div
      class="w-checkbox__input"
      @click="
        $refs.input.focus();
        $refs.input.click();
      "
      :class="this.color"
    >
      <svg width="11px" height="9px" viewbox="0 0 12 9">
        <polyline points="1 5 4 8 10 2"></polyline>
      </svg>
    </div>
    <template v-if="hasLabel && !labelOnLeft"
      ><label
        class="w-checkbox__label w-form-el-shakable pl2"
        v-if="$slots.default"
        :for="`w-checkbox--${_.uid}`"
      >
        <slot></slot> </label
      ><label
        class="w-checkbox__label w-form-el-shakable pl2"
        v-else-if="label"
        :for="`w-checkbox--${_.uid}`"
        v-html="label"
      ></label
    ></template>
  </component>
</template>
<script>
  import {
    ref,
    computed,
    reactive,
    toRefs,
    getCurrentInstance,
    watch,
  } from "vue";
  export default {
    name: "w-checkbox",

    inject: {
      wCheckboxes: { default: null },
      formRegister: { default: null },
    },

    props: {
      modelValue: { default: false }, // v-model to check or uncheck.
      // When `value` is taken by a v-model and multiple w-checkbox are plugged on
      // the same v-model, this allow returning to the v-model a custom value.
      returnValue: {},
      label: { type: String },
      labelOnLeft: { type: Boolean },
      color: { type: String, default: "primary" },
      noRipple: { type: Boolean },
      indeterminate: { type: Boolean },
      round: { type: Boolean },
      // Also name, disabled, readonly, required and validators in the mixin.
      name: { type: String }, // When sending data through form.
      disabled: { type: Boolean },
      readonly: { type: Boolean },
      required: { type: Boolean },
      validators: { type: Array },
    },

    emits: ["input", "update:modelValue", "focus", "blur"],
    setup(props, ctx) {
      const instance = getCurrentInstance();
      const isChecked = ref(props.modelValue);
      const valid = ref(null);
      const ripple = reactive({
        start: false,
        end: false,
        timeout: null,
      });
      const hasLabel = computed(() => {
        return props.label || ctx.slots.default;
      });
      const classes = computed(() => {
        return {
          [`w-checkbox w-checkbox--${
            isChecked.value ? "checked" : "unchecked"
          }`]: true,
          "w-checkbox--disabled": props.disabled,
          "w-checkbox--indeterminate": props.indeterminate,
          "w-checkbox--ripple": ripple.start,
          "w-checkbox--rippled": ripple.end,
          "w-checkbox--round": props.round,
        };
      });

      const inputName = computed(() => {
        return (
          props.name || `${instance.type.name}--${instance.type.uid || instance.uid}`
        );
      });

      function onInput() {
        isChecked.value = !isChecked.value;
        ctx.emit("update:modelValue", isChecked.value);
        ctx.emit("input", isChecked.value);

        if (!props.noRipple) {
          if (isChecked.value) {
            ripple.start = true;
            ripple.timeout = setTimeout(() => {
              ripple.start = false;
              ripple.end = true;
              setTimeout(() => (ripple.end = false), 100);
            }, 700);
          } else {
            ripple.start = false;
            clearTimeout(ripple.timeout);
          }
        }
      }

      watch(
        () => props.modelValue,
        (value) => {
          isChecked.value = value;
        }
      );

      return {
        valid,
        isChecked,
        ...toRefs(ripple),
        hasLabel,
        classes,
        inputName,
        onInput,
      };
    },
  };
</script>
